<template>
  <section>享元模式</section>
</template>

<script>
/**
 * @Description:享元模式
 * @author ZY
 * @date 2022/11/23 22:41
 */
export default {
  name: "DesignEnjoy",
  data() {
    return {}
  },
  created() {
    console.log('*******享元模式开始********')
    this.main()
    console.log('*******享元模式结束********')
  },
  methods: {
    /*
    * 享元模式：运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象，而这些对象都很相似，状态变化很小，
    * 可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象，因此它又称为轻量级模式，它是一种对象结构型模式
    * 场景： 文件上传需要创建多个文件实例的时候
如果一个应用程序使用了大量的对象，而这些大量的对象造成了很大的存储开销时就应该考虑使用享元模式
            一个操作中含有大量的分支语句，而且这些分支语句依赖于该对象的状态
    * */
    main() {
      let examCarNum = 0         // 驾考车总数
      /* 驾考车对象 */
      class ExamCar {
        constructor(carType) {
          examCarNum++
          this.carId = examCarNum
          this.carType = carType ? '手动档' : '自动档'
          this.usingState = false    // 是否正在使用
        }

        /* 在本车上考试 */
        examine(candidateId) {
          return new Promise((resolve => {
            this.usingState = true
            console.log(`考生- ${ candidateId } 开始在${ this.carType }驾考车- ${ this.carId } 上考试`)
            setTimeout(() => {
              this.usingState = false
              console.log(`%c考生- ${ candidateId } 在${ this.carType }驾考车- ${ this.carId } 上考试完毕`, 'color:#f40')
              resolve()                       // 0~2秒后考试完毕
            }, Math.random() * 2000)
          }))
        }
      }

      /* 手动档汽车对象池 */
      let ManualExamCarPool;
      ManualExamCarPool = {
        _pool: [],                  // 驾考车对象池
        _candidateQueue: [],        // 考生队列

        /* 注册考生 ID 列表 */
        registCandidates(candidateList) {
          candidateList.forEach(candidateId => this.registCandidate(candidateId))
        },

        /* 注册手动档考生 */
        registCandidate(candidateId) {
          const examCar = this.getManualExamCar()    // 找一个未被占用的手动档驾考车
          if (examCar) {
            examCar.examine(candidateId)           // 开始考试，考完了让队列中的下一个考生开始考试
                .then(() => {
                  const nextCandidateId = this._candidateQueue.length && this._candidateQueue.shift()
                  nextCandidateId && this.registCandidate(nextCandidateId)
                })
          } else this._candidateQueue.push(candidateId)
        },

        /* 注册手动档车 */
        initManualExamCar(manualExamCarNum) {
          for (let i = 1; i <= manualExamCarNum; i++) {
            this._pool.push(new ExamCar(true))
          }
        },

        /* 获取状态为未被占用的手动档车 */
        getManualExamCar() {
          return this._pool.find(car => !car.usingState)
        }
      }

      ManualExamCarPool.initManualExamCar(3)          // 一共有3个驾考车
      ManualExamCarPool.registCandidates([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  // 10个考生来考试
    }
  }
}
</script>

<style scoped>

</style>
